﻿#include <stdio.h>
#include <stdlib.h>
#include "uv.h"
#include <time.h>

uv_loop_t loop;
uv_tcp_t client;
sockaddr_in saddr;
uv_connect_t conn;
int nerror;
uv_timer_t timer;

void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
    // read buffer new
    buf->base = new char[suggested_size];// 建议值一般是65536
    buf->len = suggested_size;
    fprintf(stdout, "alloc buffer\n");
}

void after_write(uv_write_t *req, int status) {
    if (status) {
        fprintf(stderr, "write error %s\n", uv_strerror(status));
    }
    delete[] (char*)req->data; // read buffer delete
    delete req;
    fprintf(stdout, "delete buffer\n");
}

void write_one(uv_stream_t* stream, char* pData, int nLen){
    uv_write_t* w_req = new uv_write_t;
    uv_buf_t realBuff = uv_buf_init(pData, nLen);
    w_req->data = (void*)pData;
    uv_write(w_req, stream, &realBuff, 1, after_write);
}

void after_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
    // 读取完成
    fprintf(stdout, "read len %d\n", nread);
    if( nread > 0 ){
        fprintf(stdout, "=== %s\n", buf->base);

        //write_one(client, buf->base, nread);
    }
    if( nread < 0 ){
        if( nread != UV__EOF )
            fprintf(stderr, "read error: %s\n", uv_strerror(nread));
        uv_close((uv_handle_t*)client, NULL);
        delete[] buf->base;
        fprintf(stdout, "read break, clean!\n");
        uv_stop(&loop); // exit
    }
}

void on_connect(uv_connect_t* req, int status){
    if( status < 0 ){
        fprintf(stderr, "connect error: %s\n", uv_strerror(status));
        uv_stop(&loop); // exit
        return;
    }
    fprintf(stdout, "Handle: %08X %08X\n", &client, req->handle);

    // read
    uv_read_start((uv_stream_t*)&client, alloc_buffer, after_read);
}

void cb_timer(uv_timer_t* handle){
    if( !uv_is_active((uv_handle_t*)&client) ){
        uv_close((uv_handle_t*)handle, NULL);
        return;
    }
    char* pData = new char[512];
    sprintf(pData, "req id: %ld", time(NULL));
    write_one((uv_stream_t*)&client, pData, strlen(pData)+1 );
    fprintf(stdout, "write on timer.\n");
}

int main(int argc, char* argv[]){
    fprintf(stdout, "tcp client demo\n");
    uv_loop_init(&loop);
    uv_tcp_init(&loop, &client);
    uv_timer_init(&loop, &timer);

    uv_ip4_addr("127.0.0.1", 9090, &saddr);
    // 无论成功失败，都会调用on_connect
    nerror = uv_tcp_connect(&conn, &client, (const sockaddr*)&saddr, on_connect);

    uv_timer_start(&timer, cb_timer, 2000, 3000);
    nerror = uv_run(&loop, UV_RUN_DEFAULT);
    if( nerror ){
        fprintf(stderr, "run error: %s\n", uv_strerror(nerror));
        return 1;
    }
    // clean
    uv_close((uv_handle_t*)&timer, NULL);
    uv_loop_close(&loop);
    return nerror;
}
